package win.demonlegion.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuples;
import win.demonlegion.disruptor.module.LongEvent;
import win.demonlegion.module.DynamicBean;
import win.demonlegion.module.TestBean;
import win.demonlegion.module.UserBean;
import win.demonlegion.service.inte.*;
import win.demonlegion.thirdparty.config.WechatPayMerchantConfig;
import win.demonlegion.thirdparty.module.BriefWeatherCondition;
import win.demonlegion.thirdparty.response.UnifiedOrderResponse;
import win.demonlegion.thirdparty.service.AliyunOssService;
import win.demonlegion.thirdparty.service.MojiWeatherService;
import win.demonlegion.thirdparty.service.WechatPayMerchantService;
import win.demonlegion.util.*;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;


/**
 * Created by mk on 2017/6/12.
 * 测试spring boot 功能的实例
 */
@RestController
@CrossOrigin
@RequestMapping("demo")
public class DemoController {
    private static Logger logger = LoggerFactory.getLogger(DemoController.class);
    @Autowired
    private UserService userService;
    @Autowired
    private QuartzService quartzService;
    @Autowired
    private AliyunOssService aliyunOssService;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private ByteCacheService byteCacheService;
    @Autowired
    private DynamicService dynamicService;
    @Autowired
    private MojiWeatherService mojiWeatherService;
    @Autowired
    private WechatPayMerchantService wechatPayMerchantService;
    @Autowired
    private Disruptor<LongEvent> disruptor;
    @Autowired
    private TestService testService;
//    @Autowired
//    private RedisLockService redisLockService;

    @RequestMapping("file2base64")
    public String file2Base64(MultipartFile file) throws Exception {
        return Base64Util.toBase64(file.getBytes());
    }

    @RequestMapping("hello")
    public String hello(@RequestBody String body) {
        JSONObject jsonObject = JSON.parseObject(body);
        StringBuilder text = new StringBuilder(jsonObject.getString("field"));
        return text.reverse().toString();
    }

    @RequestMapping("ip")
    public String ipTest(HttpServletRequest request) {
        logger.debug(request.getRemoteAddr());
        return ResultUtil.getResult(request.getRemoteAddr());
    }

    @RequestMapping("lock")
    public String lockTest() {
//        String uuid = GuidUtil.getUuid();
        String uuid = "efb3f9ae002e46049a02a8a9c468c505";
//        boolean result = redisLockService.lock(uuid);
//        logger.debug(result+"");
//        result = redisLockService.unlock(uuid);
//        logger.debug(result+"");
        return ResultUtil.getResult(uuid);
    }

    @RequestMapping("unlock")
    public String unlockTest(String uuid) {
//        boolean result = redisLockService.unlock(uuid);
//        logger.debug(result+"");
        return ResultUtil.getResult("unlock success");
    }

    @RequestMapping("hashcode")
    public String getHashCode() {
        Date now = TimestampUtil.getDatetime();
        TestBean testBean = new TestBean();
        testBean.setValue("test");
        testBean.setTime(now);
        String params = RequestUtil.getParameters(testBean, false);
        String md5 = MD5Util.MD5(params);
        logger.debug(md5);

        testBean.setValue("demo");
        testBean.setTime(TimestampUtil.getDatetime());
        params = RequestUtil.getParameters(testBean, false);
        md5 = MD5Util.MD5(params);
        logger.debug(md5);

        testBean.setValue("test");
        testBean.setTime(now);
        params = RequestUtil.getParameters(testBean, false);
        md5 = MD5Util.MD5(params);
        logger.debug(md5);

        return "success";
    }

    @RequestMapping("uid")
    public String guid() {
        return ResultUtil.getResult(GuidUtil.getUuid());
    }

    @RequestMapping("uids")
    public String guids(@RequestParam(required = false, defaultValue = "1") int num) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add(GuidUtil.getUuid());
        }
        return ResultUtil.getResult(list);
    }

    @RequestMapping("quartz")
    public String quartzDemo() {
        quartzService.demoQuartzEvent();
        return ResultUtil.getResult(System.currentTimeMillis());
    }

    // 上传图片
    @RequestMapping("upload/file")
    public String uploadFile(MultipartFile file) {
        try {
//            String fileUrl = aliyunOssService.putImage(file.getOriginalFilename(), file.getInputStream());
            JSONObject jsonObject = UploadUtil.uploadFile("video", file.getOriginalFilename(), file.getInputStream());
            return ResultUtil.getResult(jsonObject);
        } catch (IOException ex) {
            logger.error(ex.getMessage());
            return null;
        }
    }

    @RequestMapping("push")
    public String push(String file, String key) {
        Path path = Paths.get(file);
        if (Files.exists(path)) {
            double fileSize = path.toFile().length() / 1024 / 1024;
            byte[] buffer = new byte[1024 * 1024];
            try {
                BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(path));

                int i = 0;
                while (bis.read(buffer) != -1) {
                    logger.debug(i + ": " + (i / fileSize * 100) + "%");
                    byteCacheService.rightPushValue(key, buffer);
                    i++;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "success";
        } else return "file not exist";
    }

    @RequestMapping("pull")
    public String pull(String file, String key) {
        Path path = Paths.get(file);
        try {
            Files.deleteIfExists(path);
            long listSize = byteCacheService.getListSize(key);
            logger.debug(listSize + "");
            long time = listSize / 10;
            if (time > 0) {
                for (int i = 0; i <= time; i++) {
                    List<byte[]> data = null;
                    if (i != time) {
                        data = byteCacheService.getSubList(key,
                                10 * i, 10 * (i + 1) - 1);
                        logger.debug(i * 100 / time + "%");
                    } else {
                        data = byteCacheService.getSubList(key,
                                10 * i, -1);
                        logger.debug("100%");
                    }
                    for (byte[] buffer : data) {
                        FileUtils.writeByteArrayToFile(path.toFile(), buffer, true);
                    }
                }
            } else {
                List<byte[]> data = byteCacheService.getList(key);
                for (byte[] buffer : data) {
                    FileUtils.writeByteArrayToFile(path.toFile(), buffer, true);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "success";
    }

    @RequestMapping("wechat/merchant/pay")
    public String wechatMerchantPayTest() {
        String subAppid = "wx9751e4c029c621dd";
        String subMchId = "1503052901";
        String subOpenid = "oiXz7srouDpUhRPibIGafwO-78bI";
        String body = "未度微信支付服务商接入费";
        String detail = "未度ERP服务费";
        String outTradeNo = RandomUtil.getRandomString(16);
        int totalFee = 101;
        String ip = "180.168.217.155";
        String tradeType = WechatPayMerchantConfig.TRADE_TYPE_JSAPI;
        String productId = RandomUtil.getRandomCode(16);
        UnifiedOrderResponse unifiedOrderResponse =
                wechatPayMerchantService.unifiedOrderMerchant(subAppid, subMchId, subOpenid, body, detail, outTradeNo,
                        totalFee, ip, tradeType, productId);
        return ResultUtil.getResult(unifiedOrderResponse);
    }

    @RequestMapping("transcoding")
    public String upload(String url) {
        return UploadUtil.reTranscodingVideo(url);
    }

    @RequestMapping("userlist")
    public String userlist(String keyword, int vaCode,
                           @RequestParam(required = false, defaultValue = "1") int pageNum,
                           @RequestParam(required = false, defaultValue = "20") int pageSize) {
        logger.debug("pageNum=" + pageNum + "; pageSize=" + pageSize);
//        PageHelper.startPage(pageNum, pageSize, false);
        List<UserBean> list = userService.selectUserByKeyword(keyword, vaCode);
        return ResultUtil.getResult(list);
    }

    @RequestMapping("batch")
    public String batchRedisTest(String batchData) {
        int dynamicCount = dynamicService.count();
        int pageNum = dynamicCount / 20 + 1;
        logger.debug(pageNum + "");
        for (int i = 1; i <= pageNum; i++) {
            PageHelper.startPage(i, 20, false);
            List<DynamicBean> list = dynamicService.findAll();
            if (list != null && list.size() > 0) {
                for (DynamicBean dynamicBean : list) {
                    cacheService.setCache(dynamicBean.getId(), JSON.toJSONString(dynamicBean));
                }
            }
        }
        return "success";
    }

    @RequestMapping("/sse")
    public Flux<ServerSentEvent<Integer>> randomNumbers() {
        return Flux.interval(Duration.ofSeconds(1))
                .map(seq -> Tuples.of(seq, ThreadLocalRandom.current().nextInt()))
                .map(data -> ServerSentEvent.<Integer>builder()
                        .id(Long.toString(data.getT1()))
                        .data(data.getT2())
                        .build());
    }

    @RequestMapping("weather")
    private String mojiWeatherDemo() {
        BriefWeatherCondition briefWeatherCondition = mojiWeatherService.briefWeatherCondition();
        return ResultUtil.getResult(briefWeatherCondition);
    }

    @RequestMapping("disruptor")
    public void disruptor() throws InterruptedException {
        // Executor that will be used to construct new threads for consumers
        //Executor executor = Executors.newCachedThreadPool();

        // Specify the size of the ring buffer, must be power of 2.
        //int bufferSize = 1024;

        // Construct the Disruptor
        //Disruptor<LongEvent> disruptor = new Disruptor<>(new LongEventFactory(), bufferSize, executor);

        // Connect the handler
        //disruptor.handleEventsWith(new LongEventHandler());

        // Start the Disruptor, starts all threads running
        //disruptor.start();

        // Get the ring buffer from the Disruptor to be used for publishing.
        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();

        ByteBuffer bb = ByteBuffer.allocate(8);
        for (long l = 0; l<1000; l++) {
            bb.putLong(0, l);
            ringBuffer.publishEvent((event, sequence, buffer) -> event.setValue(buffer.getLong(0)), bb);
            Thread.sleep(100);
        }
    }

    @RequestMapping("cache/init")
    public String initCache() {
        for (int i=0;i<1;i++) {
            TestBean testBean = new TestBean();
            testBean.setValue(RandomUtil.getRandomString(32));
            testService.add(testBean);
        }
        return "success";
    }

    @RequestMapping("cache/{id}")
    public String fetchCache(@PathVariable("id") long id) {
        return JSON.toJSONString(testService.fetch(id));
    }
}
